﻿package kit4j.common.command.executor;

import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

import kit4j.common.command.Command;
import kit4j.common.command.CommandUncaughtExceptionHandler;

/**
 * Command对象的执行者，所有被添加的Command对象将被同步执行。 所有Command对象执行过程中抛出的异常不会从方法SynchronousCommandExecutor.execute方法抛出，客户可调用
 * SynchronousCommandExecutor .setCommandUncaughtExceptionHandler(CommandUncaughtExceptionHandler)方法设置异常的捕获
 * 对象对抛出的异常进行捕获并处理。
 * 
 * @author MiniKnife
 * 
 */
public class SynchronousCommandExecutor implements CommandExecutor {

	/**
	 * Command对象集。
	 */
	private List<Command> cmdList;

	/**
	 * Command执行线程的执行对象。
	 */
	private Executor executor;

	/**
	 * Command对象执行过程中异常的捕获对象。
	 */
	private CommandUncaughtExceptionHandler handler;

	/**
	 * 构造一个新的SynchronousCommandExecutor对象。
	 */
	public SynchronousCommandExecutor() {
		cmdList = new LinkedList<Command>();
	}

	/**
	 * @see CommandExecutor#addCommand(Command)
	 */
	@Override
	public void addCommand(Command cmd) {
		cmdList.add(cmd);
	}

	/**
	 * @see CommandExecutor#removeCommand(Command)
	 */
	@Override
	public void removeCommand(Command cmd) {
		cmdList.remove(cmd);
	}

	/**
	 * 同步执行所有的Command对象。 <br />
	 * 如果某一个Command对象在执行过程中抛出异常，该异常将被指定的{@link kit4j.common.command.CommandUncaughtExceptionHandler} 对象捕获。
	 * 
	 * @throw Exception Command对象执行过程中抛出的异常
	 */
	@Override
	public void execute() throws Exception {
		executor = Executors.newCachedThreadPool();

		for (Command c : cmdList) {
			final Command cmd = c;
			executor.execute(new Runnable() {
				public void run() {
					try {
						cmd.execute();
					} catch (Exception e) {
						throwedException(cmd, e);
					}
				}
			});
		}
	}

	/**
	 * @return Command对象运行时抛出的异常的捕获者。
	 */
	public CommandUncaughtExceptionHandler getCommandUncaughtExceptionHandler() {
		return handler;
	}

	/**
	 * 设置Command对象运行时抛出的异常的捕获者。
	 * 
	 * @param handler
	 *            要设置的异常捕获者
	 */
	public synchronized void setCommandUncaughtExceptionHandler(CommandUncaughtExceptionHandler handler) {
		this.handler = handler;
	}

	/**
	 * 有Command对象在运行时抛出异常时，将调用该方法通知异常捕获器捕获异常。
	 * 
	 * @param c
	 *            抛出异常的Command对象
	 * @param e
	 *            抛出的异常
	 */
	private synchronized void throwedException(Command c, Exception e) {
		if (getCommandUncaughtExceptionHandler() != null) {
			getCommandUncaughtExceptionHandler().uncaughtException(c, e);
		}
	}

}
